
#include <stdio.h>
#include <stdint.h>
#include "my_gpio.h"
#include "my_key_drv.h"
#include "sys_param.h"
#include "my_dac.h"
#include "my_buzzer.h"

#define EVENT_CB(ev)   if(handle->cb[ev])handle->cb[ev]((BUTTON_S*)handle)

//static GPIO_InitTypeDef GPIO_Handle;
//button handle list head.
static BUTTON_S *head_handle = NULL;
//  PA7,PA6 ----TP按键检测脚（平时为高电平，低电平表示按键按下）



uint8_t key_get_gpio_value(BUTTON_S *handle)
{
//    printf("key read port:%d,pin:%d \r\n", handle->port, handle->pin);
    //return gpio_read_pin(handle->port, handle->pin);
	return GPIO_ReadInputDataBit(handle->port, handle->pin);
}

/**
  * @brief  Initializes the button struct handle.
  * @param  handle: the button handle strcut.
  * @param  pin_level: read the HAL GPIO of the connet button level.
  * @param  active_level: pressed GPIO level.
  * @retval None
  */
void button_init(BUTTON_S *handle, GPIO_Module* port, uint16_t pin, uint8_t active_level)
{
	memset(handle, 0, sizeof(BUTTON_S));

    handle->port = port;
    handle->pin = pin;
	handle->event = (uint8_t)NONE_PRESS;
	handle->active_level = active_level;
	//handle->user_data = user_data;
	//handle->hal_button_Level = pin_level;
	handle->button_level = key_get_gpio_value(handle);
}

/**
  * @brief  Attach the button event callback function.
  * @param  handle: the button handle strcut.
  * @param  event: trigger event type.
  * @param  cb: callback function.
  * @retval None
  */
void button_attach(BUTTON_S *handle, PRESS_EVT event, btn_callback cb)
{
	handle->cb[event] = cb;
}

/**
  * @brief  Inquire the button event happen.
  * @param  handle: the button handle strcut.
  * @retval button event.
  */
PRESS_EVT button_get_event(BUTTON_S *handle)
{
	return (PRESS_EVT)(handle->event);
}

/**
  * @brief  BUTTON_S driver core function, driver state machine.
  * @param  handle: the button handle strcut.
  * @retval None
  */
void button_handler(BUTTON_S *handle)
{
	//uint8_t read_gpio_level = handle->hal_button_Level(handle);


    uint8_t read_gpio_level = key_get_gpio_value(handle);
//    printf("read_gpio_level :%d\r\n", read_gpio_level);

	//ticks counter working..       
	if ((handle->state) > 0) handle->ticks++;

	/*------------button debounce handle---------------*/
	if (read_gpio_level != handle->button_level) { //not equal to prev one
		//continue read 3 times same new level change
		if (++(handle->debounce_cnt) >= DEBOUNCE_TICKS) {
			handle->button_level = read_gpio_level;
			handle->debounce_cnt = 0;
		}
	} else   //leved not change ,counter reset.
		handle->debounce_cnt = 0;

	/*-----------------State machine-------------------*/
	switch (handle->state) {
	case 0:
		if (handle->button_level == handle->active_level) {	//start press down
			handle->event = (uint8_t)PRESS_DOWN;
			EVENT_CB(PRESS_DOWN);
			handle->ticks = 0;
			handle->repeat = 1;
			handle->state = 1;
		} else
			handle->event = (uint8_t)NONE_PRESS;
		break;

	case 1:
		if (handle->button_level != handle->active_level) { //released press up

			// if(handle->ticks > LONG_TICKS)           // 长按抬起
			// {
			// 	handle->event = (uint8_t)LONG_PRESS_UP;
			// 	EVENT_CB(LONG_PRESS_UP);
			// }
			// else
			{
				handle->event = (uint8_t)PRESS_UP;
				EVENT_CB(PRESS_UP);
			}

			// handle->ticks = 0;
			handle->state = 2;

		} else if (handle->ticks > LONG_TICKS) {
			handle->event = (uint8_t)LONG_PRESS_START;
			EVENT_CB(LONG_PRESS_START);
			handle->state = 5;
		}
		break;

	case 2:
		if (handle->button_level == handle->active_level) { //press down again
			handle->event = (uint8_t)PRESS_DOWN;
			EVENT_CB(PRESS_DOWN);
			handle->repeat++;
			if (handle->repeat == 2) {
				EVENT_CB(DOUBLE_CLICK); // repeat hit
			}
			EVENT_CB(PRESS_REPEAT); // repeat hit
			handle->ticks = 0;
			handle->state = 3;
		} else if ((handle->ticks > MIN_SHORT_TICKS)&&(handle->ticks < MAX_SHORT_TICKS)) { //released timeout
			if (handle->repeat == 1) {
				handle->event = (uint8_t)SINGLE_CLICK;
				EVENT_CB(SINGLE_CLICK);
			} else if (handle->repeat == 2){
				handle->event = (uint8_t)DOUBLE_CLICK;
			}
			handle->state = 0;
			printf("key_tick:%d ms \r\n", 10 * handle->ticks);
		} else {
			handle->state = 0;
			printf("key_tick:%d ms ,key_state to [0]\r\n", 10 * handle->ticks);

		}
		break;

	case 3:
		if (handle->button_level != handle->active_level) { //released press up
			handle->event = (uint8_t)PRESS_UP;
			EVENT_CB(PRESS_UP);
			if ((handle->ticks < MIN_SHORT_TICKS)) {
				handle->ticks = 0;
				handle->state = 2; //repeat press
			} else
				handle->state = 0;
		}
		break;

	case 5:
		if (handle->button_level == handle->active_level) {
			//continue hold trigger
			handle->event = (uint8_t)LONG_PRESS_HOLD;
			EVENT_CB(LONG_PRESS_HOLD);

		} else { //releasd
			handle->event = (uint8_t)PRESS_UP;
			EVENT_CB(PRESS_UP);
			handle->state = 0; //reset
		}
		break;
	}
}


// 模式按键 、 开/关机按键 --------------
static void power_mode_key_short_press_cb()
{
	if(SLEEP_STA == get_sys_state()){
		return;
	}

	printf("power_mode_key_short_press_cb, mode ++\r\n");
	sys_data.mode ++;
//	ems_playlod1_stop();
// 
//	ems_output_disable();
	sys_data.level = LEVEL_1;
	if(sys_data.mode > HAIR_MODE){
		sys_data.mode = EYE_MODE;
	}
	else{
//		ems_voltage_select();
	}
	//buzzer_on_with_param(10, 10, 4);
//	buzzer_shor_on();
//	motor_shor_on();
}
static void power_mode_key_double_press_cb()
{
	printf("power_mode_key_double_press_cb\r\n");
}
static void power_mode_key_long_press_cb()
{
	printf("power_mode_key_long_press_cb\r\n");

	if(SLEEP_STA == sys_data.sta){
		sys_data.sys_power_on_flag = 1;
	}
	else{
		sys_data.sta = SLEEP_STA;
		sys_data.sys_power_off_flag = 1;
	}
}
static void power_mode_key_hold_press_cb()
{
	// printf("power_mode_key_hold_press_cb\r\n");
}


//------------ems  档位 + ------
static void level_add_key_short_press_cb()
{
	printf("level_add_key_short_press_cb\r\n");
	sys_data.level ++;
	if(sys_data.level > LEVEL_MAX){
		sys_data.level = LEVEL_MAX;
	}
//	ems_voltage_select();
//	buzzer_shor_on();
//	motor_shor_on();
}
static void level_add_key_double_press_cb()
{
	printf("level_add_key_double_press_cb\r\n");
}
static void level_add_key_long_press_cb()
{
	printf("level_add_key_long_press_cb\r\n");
}
static void level_add_key_hold_press_cb()
{
	// printf("level_add_key_hold_press_cb\r\n");
}

// -------------led 档位----------
static void level_dec_key_short_press_cb()
{
	printf("level_dec_key_short_press_cb\r\n");
	if(sys_data.level >= LEVEL_1){
		sys_data.level --;
	}
//	ems_voltage_select();
//	buzzer_shor_on();
//	motor_shor_on();
}

static void level_dec_key_double_press_cb()
{
	printf("level_dec_key_double_press_cb\r\n");
}
static void level_dec_key_long_press_cb()
{
	printf("level_dec_key_long_press_cb\r\n");
}
static void level_dec_key_hold_press_cb()
{
	// printf("level_dec_key_hold_press_cb\r\n");
}

// static void key_gpio_config(uint8_t port, uint8_t pin, uint8_t active_level)
void key_gpio_config(GPIO_Module* GPIOx, uint16_t pin, uint8_t active_level)
{

    //  // gpio input
    // GPIO_Handle.Pin   = pin;
    // GPIO_Handle.Mode  = GPIO_MODE_INPUT;
    
	// if(active_level){
    //     GPIO_Handle.Pull = GPIO_PULLDOWN;
    // }
	// else{
    //     GPIO_Handle.Pull = GPIO_PULLUP;
    // }
    // gpio_init(port, &GPIO_Handle); 

	GPIO_PuPdType pu_pd_mod;

	if(HIGH_LEVEL_TRIGGER == active_level){
        pu_pd_mod = GPIO_Pull_Down;
    }
	else{
        pu_pd_mod = GPIO_Pull_Up;
    }

	gpio_input_cfg(GPIOx, pin, pu_pd_mod);    
}

//--------------------------------

/**
  * @brief  Start the button work, add the handle into work list.
  * @param  handle: target handle strcut.
  * @retval 0: succeed. -1: already exist.
  */
int button_start(BUTTON_S *handle)
{
	BUTTON_S *target;
	// rtos_lock_mutex(&g_key_mutex);
	target = head_handle;
	while (target) {
		if (target == handle) {
			// rtos_unlock_mutex(&g_key_mutex);
			return -1;	//already exist.
		}
		target = target->next;
	}
	handle->next = head_handle;
	head_handle = handle;
	// rtos_unlock_mutex(&g_key_mutex);
	return 0;
}


int key_item_configure(GPIO_Module* port, uint16_t pin, uint8_t active_level, void short_press(void *), 
                        void double_press(void *),
						void long_press(void *),  void hold_press(void *))
{
	BUTTON_S *handle;
	int result;

	handle = (BUTTON_S *)malloc(sizeof(BUTTON_S));
	if (NULL == handle){
        return -2;
    }
		
	key_gpio_config(port, pin, active_level);
	button_init(handle, port, pin, active_level);
	button_attach(handle, SINGLE_CLICK, (btn_callback)short_press);
	button_attach(handle, DOUBLE_CLICK, (btn_callback)double_press);
	button_attach(handle, LONG_PRESS_START,	(btn_callback)long_press);
	button_attach(handle, LONG_PRESS_HOLD, (btn_callback)hold_press);

	result = button_start(handle);
	if (result < 0) {
		printf("button_start failed\n");
		free(handle);
		return -1;
	}
	printf("key_item_configure\r\n");

	return 0;
}



/***********************************************************
 * @fn      gpio_demo
 * @brief   gpio demo
 * @param   fe_Demo: demo select. 
 */
void my_key_scanf(void)
{
	BUTTON_S *target;
	// rtos_lock_mutex(&g_key_mutex);
	//printf("my_key_scanf\r\n");
	for (target = head_handle; target; target = target->next)
    {
        button_handler(target);
    }
	// rtos_unlock_mutex(&g_key_mutex);
}



/***********************************************************
 * @fn      gpio_demo
 * @brief   gpio demo
 * @param   fe_Demo: demo select. 
 */
void my_key_init(void)
{
	printf("my_key_init\r\n");
	
    key_item_configure(POWER_MODE_KEY_PORT, POWER_MODE_KEY_PIN, LOW_LEVEL_TRIGGER, 
                        power_mode_key_short_press_cb, power_mode_key_double_press_cb, 
						power_mode_key_long_press_cb, power_mode_key_hold_press_cb);
   
    key_item_configure(LEVEL_ADD_KEY_PORT, LEVEL_ADD_KEY_PIN, LOW_LEVEL_TRIGGER, 
                    	level_add_key_short_press_cb, level_add_key_double_press_cb,
					 	level_add_key_long_press_cb, level_add_key_hold_press_cb);

	// key_item_configure(LEVEL_DEC_KEY_PORT, LEVEL_DEC_KEY_PIN, LOW_LEVEL_TRIGGER, 
    //                 	level_dec_key_short_press_cb, level_dec_key_double_press_cb, 
	// 					level_dec_key_long_press_cb, level_dec_key_hold_press_cb);				
}
